package b_nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class NIOSelectorServer {

    public static void main(String[] args) throws Exception {
        // 1.打开一个服务端通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        // 2.绑定对应的端口号
        serverChannel.bind(new InetSocketAddress(9999));
        // 3.通道默认是阻塞的，需要设置为非阻塞
        serverChannel.configureBlocking(false);
        // 4.创建选择器
        Selector selector = Selector.open();
        // 5.将服务端通道注册到选择器上，并指定注册监听的事件为OP_ACCEPT
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            // 6.检查选择器是否有事（阻塞2秒）
            int select = selector.select(2000);
            if (select == 0) continue;
            // 7.获取事件集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 8.判断事件是否是客户端连接事件
                if (key.isAcceptable()) {
                    // 9.得到客户端通道
                    SocketChannel clientChannel = serverChannel.accept();
                    System.out.println("客户端已连接......" + clientChannel);
                    // 必须设置通道为非阻塞，因为selector需要轮询监听每个通道的事件
                    clientChannel.configureBlocking(false);
                    // 并将通道注册到选择器上，指定监听事件为OP_READ
                    clientChannel.register(selector, SelectionKey.OP_READ);
                }
                // 10.判断是否是客户端读就绪事件
                if (key.isReadable()) {
                    // 11.得到客户端通道，读取数据到缓冲区
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int read = socketChannel.read(byteBuffer);
                    if (read != 0) {
                        System.out.println("客户端消息:" + new String(byteBuffer.array(),
                                0, read, StandardCharsets.UTF_8));
                    }
                    // 12.给客户端回写数据
                    socketChannel.write(ByteBuffer.wrap(
                            "回复信息".getBytes(StandardCharsets.UTF_8)));
                    socketChannel.close();
                }
                // 13.从集合中删除对应的事件，防止二次处理
                iterator.remove();
            }
        }
    }
}
